package com.meilai.project.util;

import com.meilai.project.util.interf.OssUtilInterface;
import lombok.extern.log4j.Log4j2;
import org.apache.http.Header;
import org.apache.http.client.methods.*;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * @author 张驰
 * @description
 * @date 2022-09-21 09:18
 */
@Component
@Log4j2
public class ObsCtyunUtil implements OssUtilInterface {
    @Value("${ctyun.obs.accessKeyId}")
    private String accessKey;
    @Value("${ctyun.obs.accessKeySecret}")
    private String securityKey;
    @Value("${ctyun.obs.bucketName}")
    private String bucketName;
    @Value("${ctyun.obs.domain}")
    private String domain;
    @Value("${ctyun.obs.endpoint}")
    private String endpoint;

    private String signWithHmacSha1(String sk, String canonicalString) throws
            UnsupportedEncodingException {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(sk.getBytes("UTF-8"),
                    "HmacSHA1");
            Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(signingKey);
            return
                    Base64.getEncoder().encodeToString(mac.doFinal(canonicalString.getBytes("UTF-8")));
        } catch (NoSuchAlgorithmException | InvalidKeyException |
                UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private String genSignature(String method,
                                HttpRequestBase httpBase,
                                String contentMD5,
                                String contentType,
                                String canonicalizedHeaders,
                                String canonicalizedResource) {
        String requesttime = DateUtil.formatDate(System.currentTimeMillis());
        httpBase.addHeader("Date", requesttime);
        // Content-MD5 、Content-Type 没有直接换行， data 格式为 RFC 1123，和请求中的时间一致
        String canonicalString = method + "\n" + contentMD5 + "\n" + contentType +
                "\n" + requesttime + "\n" + canonicalizedHeaders + canonicalizedResource;
        System.out.println("StringToSign:[" + canonicalString + "]");
        try {
            return signWithHmacSha1(securityKey, canonicalString);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private void sendRequest(String method, InputStream inputStream, String keyName){
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse httpResponse = null;

        HttpEntityEnclosingRequestBase httpBase = null;
        HttpRequestBase httpBaseSimple = null;
        boolean hasEntity = false;
        if("PUT".equalsIgnoreCase(method)) {
            httpBase = new HttpPut(generateUrl(keyName));
            hasEntity = true;
        }
        if("POST".equalsIgnoreCase(method)) {
            httpBase = new HttpPost(generateUrl(keyName));
            hasEntity = true;
        }
        if("GET".equalsIgnoreCase(method)) {
            httpBaseSimple = new HttpGet(generateUrl(keyName));
            hasEntity = false;
        }
        if("DELETE".equalsIgnoreCase(method)) {
            httpBaseSimple = new HttpDelete(generateUrl(keyName));
            hasEntity = false;
        }
        String canonicalizedResource = "/" + bucketName + "/" + keyName;

        try {
            String signature = genSignature(method, hasEntity?httpBase:httpBaseSimple,"", "", "", canonicalizedResource);
            // 签名头域 Authorization: OBS AccessKeyID:signature
            String authHeader = "OBS " + accessKey + ":" + signature;
            // 上传的文件目录
            if(hasEntity){
                InputStreamEntity entity = new InputStreamEntity(inputStream);
                httpBase.setEntity(entity);
                httpBase.addHeader("Authorization", authHeader);
            }else{
                httpBaseSimple.addHeader("Authorization", authHeader);
            }
            httpResponse = httpClient.execute(hasEntity?httpBase:httpBaseSimple);

            // 打印发送请求信息和收到的响应消息
            System.out.println("Request Message:");
            System.out.println(httpBase.getRequestLine());
            for (Header header : httpBase.getAllHeaders()) {
                System.out.println(header.getName() + ":" + header.getValue());
            }
            System.out.println("Response Message:");
            System.out.println(httpResponse.getStatusLine());
            for (Header header : httpResponse.getAllHeaders()) {
                System.out.println(header.getName() + ":" + header.getValue());
            }

            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    httpResponse.getEntity().getContent()));
            String inputLine;
            StringBuffer response = new StringBuffer();
            while ((inputLine = reader.readLine()) != null) {
                response.append(inputLine);
            }
            reader.close();
            // print result
            System.out.println(response.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void store(InputStream inputStream, long contentLength, String contentType, String keyName) {
        sendRequest("PUT", inputStream, keyName);
    }

    @Override
    public void storeSimple(InputStream inputStream, String keyName) {
        sendRequest("PUT", inputStream, keyName);
    }

    @Override
    public void delete(String keyName) {
        sendRequest("DELETE", null, keyName);
    }

    @Override
    public String generateUrl(String keyName) {
        return getBaseUrl() + keyName;
    }

    private String getBaseUrl() {
        return "https://" + domain + "/";
    }
}
